package com.smh.demo1.a14;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import javax.annotation.PostConstruct;

/**
 * @author shiminghui
 * @date 2025/4/18 9:18
 * @description: TODO
 */
public class A14_1Application {

    // 代理的实现时机 1.在bean依赖注入之前执行(有循环依赖) 2.在bean初始化之后执行
    // 当然,代理对象是不会去代理未初始化之前的方法,如构造方法,和@postConstruct注解标注的方法

    public static void main(String[] args) {


        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class); // 处理@Configuration注解,是一个beanFactory 后处理器
        context.registerBean("config", Config.class);
        context.refresh();

        System.out.println("======================================");
        System.out.println(context.getBean(Bean1.class).getClass().getName());
    }

    @Configuration
    static class Config {
        // 处理@Aspect注解
        @Bean
        public AnnotationAwareAspectJAutoProxyCreator annotationAwareAspectJAutoProxyCreator() {
            return new AnnotationAwareAspectJAutoProxyCreator();
        }

        // 处理@Autowired注解
        @Bean
        public AutowiredAnnotationBeanPostProcessor autowiredAnnotationBeanPostProcessor() {
            return new AutowiredAnnotationBeanPostProcessor();
        }

        // 处理@PostConstruct注解
        @Bean
        public CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor() {
            return new CommonAnnotationBeanPostProcessor();
        }


        @Bean
        public Advisor advisor(MethodInterceptor methodInterceptor) {
            AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
            pointcut.setExpression("execution(* foo())");
            return new DefaultPointcutAdvisor(pointcut, methodInterceptor);
        }

        @Bean
        public MethodInterceptor methodInterceptor() {
            return invocation -> {
                System.out.println("before");
                Object result = invocation.proceed();
                System.out.println("after");
                return result;
            };
        }

        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }


    }


    static class Bean1 {
        public Bean1() {
            System.out.println("Bean1()");
        }

        public void foo() {
            System.out.println("foo");
        }

        @Autowired
        public void setBean2(Bean2 bean2) {
            System.out.println("bean1 setBean2 " + bean2.getClass().getName());
        }

        @PostConstruct
        public void init() {
            System.out.println("bean1 init");
        }
    }

    static class Bean2 {
        private Bean1 bean1;

        public Bean2() {
            System.out.println("Bean2()");
        }

        @Autowired
        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
            System.out.println("bean2 setBean1 " + bean1.getClass().getName());
        }

        @PostConstruct
        public void init() {
            System.out.println("bean2 init");
        }
    }


}
